package com.linchuansi.ioc;

import com.linchuansi.di.BeanReference;
import com.linchuansi.di.PropertyValue;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * *
 *
 * @author wb
 * @date 2025-11-24 19:59*@since 1.0.0
 */
public class DefaultBeanFactory implements BeanFactory, BeanDefinitionRegistry, Cloneable {
    public Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    private Map<String, Object> singletonBeanMap = new ConcurrentHashMap<>(256);
    private Map<String, Set<String>> aliasMap = new ConcurrentHashMap<>(256);
    private Map<Class, Set<String>> typeMap = new ConcurrentHashMap<>(256);

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws Exception {
        if (!beanDefinition.validate()) {
            throw new Exception("beanDefinition=" + beanDefinition + "不合法");
        }
        if (containsBeanDefinition(beanName)) {
            throw new Exception("beanName=" + beanName + "已存在");
        }
        beanDefinitionMap.put(beanName, beanDefinition);
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanName) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        return beanDefinition;
    }

    @Override
    public boolean containsBeanDefinition(String beanName) {
        return beanDefinitionMap.containsKey(beanName);
    }

    @Override
    public Object getBean(String beanName) throws Exception {
        Object instance = singletonBeanMap.get(beanName);
        BeanDefinition beanDefinition = null;
        if (instance != null) {
            return instance;
        } else {
            beanDefinition = beanDefinitionMap.get(beanName);
            Objects.requireNonNull(beanDefinition, "beanDefinition找不到");
            if (beanDefinition.isSingleton()) {
                synchronized (singletonBeanMap) {
                    if (!singletonBeanMap.containsKey(beanName)) {
                        instance = createBean(beanName, beanDefinition);
                        singletonBeanMap.put(beanName, instance);
                    }
                }
            } else {
                instance = createBean(beanName, beanDefinition);
            }
        }
        doInit(beanDefinition, instance);
        // 给入属性依赖
        setPropertyDIValues(beanDefinition, instance);
        return instance;
    }

    @Override
    public <T> T getBean(Class<T> type) throws Exception {
        Set<String> strings = typeMap.get(type);
        if(strings != null) {
            if (strings.size() == 1) {
                return (T) getBean(strings.iterator().next());
            } else {
                //找Primary
                BeanDefinition bd = null;
                String primaryName = null;
                StringBuilder nameStrings = new StringBuilder();
                for (String name : strings) {
                    bd = this.getBeanDefinition(name);
                    if (bd != null && bd.isPrimary()) {
                        if (primaryName != null) {
                            String mess = type + " 类型的Bean存储多个Primary[" + primaryName + "," + name + "]";
                            //log.error(mess);
                            throw new Exception(mess);
                        } else {
                            primaryName = name;
                        }
                    }
                    nameStrings.append(" " + name);
                }

                if (primaryName != null) {
                    return (T) this.getBean(primaryName);
                } else {
                    String mess = type + " 类型的Bean存在多个[" + nameStrings + "] 但无法确定Primary";
                    System.out.println(mess);
                    throw new Exception(mess);
                }
            }
        }
        return null;
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws Exception {
        Set<String> names = this.typeMap.get(type);
        if(names != null) {
            Map<String, T> map = new HashMap<>();
            for(String name : names){
                map.put(name,(T) this.getBean(name));
            }
            return map;
        }
        return null;
    }

    @Override
    public Class<?> getType(String name) throws Exception {
        BeanDefinition bd = getBeanDefinition(name);
        Class<?> beanClass = bd.getBeanClass();
        if (beanClass != null) {
            if(StringUtils.isEmpty(bd.getFactoryBeanName())){

            } else {
                beanClass = beanClass.getDeclaredMethod(bd.getFactoryMethodName(),null).getReturnType();
            }
        } else {
            Object factoryBean = getBean(bd.getFactoryBeanName());
            String factoryMethodName = bd.getFactoryMethodName();
            Class<?> returnType = factoryBean.getClass().getDeclaredMethod(factoryMethodName, null).getReturnType();
            return returnType;
        }
        return beanClass;
    }

    private Object createBean(String beanName, BeanDefinition beanDefinition) throws Exception {
        Class<?> beanClass = beanDefinition.getBeanClass();
        Object instance = null;
        if (beanClass != null) {
            if (StringUtils.isEmpty(beanDefinition.getFactoryBeanName())) {
                instance = createInstanceByConstructor(beanDefinition);
            } else {
                instance = createInstanceByStaticFactoryMethod(beanDefinition);
            }
        } else {
            instance = createInstanceByInstanceFactoryMethod(beanDefinition);
        }
        return instance;
    }

    public Object createInstanceByConstructor(BeanDefinition beanDefinition) {
        Class<?> beanClass = beanDefinition.getBeanClass();
        try {
            Object instance = beanClass.newInstance();
            return instance;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("创建对象失败" + e.toString());
        }
        return null;
    }

    public Object createInstanceByStaticFactoryMethod(BeanDefinition bd) {
        Class<?> beanClass = bd.getBeanClass();
        String factoryMethodName = bd.getFactoryMethodName();
        try {
            Method method = beanClass.getMethod(factoryMethodName, null);
            Object instance = method.invoke(beanClass, null);
            return instance;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public Object createInstanceByInstanceFactoryMethod(BeanDefinition bd) throws Exception {
        Object factoryBean = getBean(bd.getFactoryBeanName());
        String factoryMethodName = bd.getFactoryMethodName();
        try {
            Method method = factoryBean.getClass().getMethod(factoryMethodName, null);
            Object instance = method.invoke(factoryBean, null);
            return instance;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public void doInit(BeanDefinition bd, Object instance) {
        if (!StringUtils.isEmpty(bd.getInitMethodName())) {
            Class<?> beanClass = bd.getBeanClass();
            try {
                Method method = beanClass.getMethod(bd.getInitMethodName(), null);
                method.invoke(instance, null);
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("初始化失败" + e.toString());
            }

        }

    }

    @Override
    public void registerAlias(String beanName, String alias) {
        Set<String> strings = aliasMap.get(beanName);
        if (CollectionUtils.isEmpty(strings)) {
            strings = new HashSet<>();
            strings.add(alias);
            aliasMap.put(beanName, strings);
        } else {
            if (!strings.contains(alias)) {
                strings.add(alias);
                aliasMap.put(beanName, strings);
            } else {
                System.out.println("别名已存在");
            }
        }
    }

    @Override
    public void removeAlias(String alias) {
        for (Map.Entry<String, Set<String>> entry : aliasMap.entrySet()) {
            Set<String> strings = entry.getValue();
            if (strings.contains(alias)) {
                strings.remove(alias);
                aliasMap.put(entry.getKey(), strings);
            }
        }
    }

    @Override
    public boolean isAlias(String beanName) {
        if (aliasMap.containsKey(beanName)) {
            return true;
        }
        return false;
    }

    @Override
    public Set<String> getAliases(String beanName) {
        Set<String> strings = aliasMap.get(beanName);
        return strings;
    }

    @Override
    public String getOriginalBeanName(String alias) {
        for (Map.Entry<String, Set<String>> entry : aliasMap.entrySet()) {
            Set<String> strings = entry.getValue();
            if (strings.contains(alias)) {
                return entry.getKey();
            }
        }
        return null;
    }
    public void registerTypeMap() throws Exception{
        for(String name : this.beanDefinitionMap.keySet()){
            Class<?> type = this.getType(name);
            //映射本类
            this.registerTypeMap(name,type);

            //父类
            this.registerSuperClassTypeMap(name,type);
            //接口
            this.registerInterfaceTypeMap(name,type);
        }

    }
    public void registerSuperClassTypeMap(String name, Class<?> type) {
        Class<?> superClass = type.getSuperclass();
        while(superClass != null){
            this.registerTypeMap(name,superClass);
            superClass = superClass.getSuperclass();
        }
    }
    public void registerInterfaceTypeMap(String name, Class<?> type) {
        Class<?>[] interfaces = type.getInterfaces();
        for(Class<?> interfaceClass : interfaces){
            this.registerTypeMap(name,interfaceClass);
        }
    }
    private void registerTypeMap(String name, Class<?> type) {
        Set<String> names2type = this.typeMap.get(type);
        if(names2type == null){
            names2type = new HashSet<>();
            this.typeMap.put(type,names2type);
        }
        names2type.add(name);
    }
    private Constructor<?> determineConstructor(BeanDefinition bd, Object[] args) throws Exception {
        /*判定构造方法的逻辑应是怎样的？
        1 先根据参数的类型进行精确匹配查找，如未找到，则进行第2步查找；
        2获得所有的构造方法，遍历，通过参数数量过滤，再比对形参类型与实参类型。
        * */

        Constructor<?> ct = null;

        //没有参数，则用无参构造方法
        if (args == null) {
            return bd.getBeanClass().getConstructor(null);
        }

        // 1 先根据参数的类型进行精确匹配查找
        Class<?>[] paramTypes = new Class[args.length];
        int j = 0;
        for (Object p : args) {
            paramTypes[j++] = p.getClass();
        }
        try {
            ct = bd.getBeanClass().getConstructor(paramTypes);
        } catch (Exception e) {
            // 这个异常不需要处理
        }

        if (ct == null) {
            // 2 没有精确参数类型匹配的，获得所有的构造方法，遍历，通过参数数量过滤，再比对形参类型与实参类型。
            // 判断逻辑：先判断参数数量，再依次比对形参类型与实参类型
            outer:
            for (Constructor<?> ct0 : bd.getBeanClass().getConstructors()) {
                Class<?>[] paramterTypes = ct0.getParameterTypes();
                if (paramterTypes.length == args.length) {   //通过参数数量过滤
                    for (int i = 0; i < paramterTypes.length; i++) { //再依次比对形参类型与实参类型是否匹配
                        if (!paramterTypes[i].isAssignableFrom(args[i].getClass())) {
                            continue outer; //参数类型不可赋值（不匹配），跳到外层循环，继续下一个
                        }
                    }

                    ct = ct0;  //匹配上了
                    break outer;
                }
            }
        }

        if (ct != null) {
            return ct;
        } else {
            throw new Exception("不存在对应的构造方法！" + bd);
        }
    }
   public Object[] getConstructorArgumentValues(BeanDefinition bd) throws Exception {
       List<?> defs = bd.getConstructorArgumentValues();
       if (CollectionUtils.isEmpty(defs)) {
           return null;
       }

       Object[] values = new Object[defs.size()];
       int i = 0;
       for (Object originalValue : defs) {
           values[i++] = getOneArgumentRealValue(originalValue); //获取真正参数值的逻辑应该是怎样的？
       }
       return values;
   }
    private Object getOneArgumentRealValue(Object originalValue) throws Exception {
        //获取真正参数值，主要是处理BeanReference,得到真正的Bean实例
        Object realValue = null;
        if (originalValue != null) {
            if (originalValue instanceof BeanReference) {
                BeanReference br = (BeanReference) originalValue;
                if (!StringUtils.isEmpty(br.getBeanName())) {
                    realValue = this.getBean(br.getBeanName());
                } else if (br.getType() != null) {
                    realValue = this.getBean(br.getType());
                }
            } else if (originalValue instanceof Object[]) {
                // TODO 处理集合中的bean引用
            } else if (originalValue instanceof Collection) {
                // TODO 处理集合中的bean引用
            } else if (originalValue instanceof Properties) {
                // TODO 处理properties中的bean引用
            } else if (originalValue instanceof Map) {
                // TODO 处理Map中的bean引用
            } else {
                realValue = originalValue;
            }
            //请大家完成上面未完成的逻辑
        }
        return realValue;
    }
    private Method determineFactoryMethod(BeanDefinition bd, Object[] args, Class<?> type) throws Exception {
       /*判定工厂方法的逻辑同构造方法的判定逻辑
        1 先根据实参的类型进行精确匹配查找，如未找到，则进行第2步查找；
        2 获得所有方法，遍历，通过方法名、参数数量过滤，再比对形参类型与实参类型。
        * */
        String methodName = bd.getFactoryMethodName();

        if (args == null) {
            return type.getMethod(methodName, null);
        }

        Method m = null;
        // 对于原型bean,从第二次开始获取bean实例时，可直接获得第一次缓存的构造方法。
        m = bd.getFactoryMethod();
        if (m != null) {
            return m;
        }

        // 1 先根据实参的类型进行精确匹配查找
        Class[] paramTypes = new Class[args.length];
        int j = 0;
        for (Object p : args) {
            paramTypes[j++] = p.getClass();
        }
        try {
            m = type.getMethod(methodName, paramTypes);
        } catch (Exception e) {
            // 这个异常不需要处理
        }

        if (m == null) {
            // 没有精确参数类型匹配的，则遍历匹配所有的方法
            // 2 获得所有方法，遍历，通过方法名、参数数量过滤，再比对形参类型与实参类型。
            outer:
            for (Method m0 : type.getMethods()) {
                if (!m0.getName().equals(methodName)) {
                    continue;
                }
                Class<?>[] paramterTypes = m.getParameterTypes();
                if (paramterTypes.length == args.length) {
                    for (int i = 0; i < paramterTypes.length; i++) {
                        if (!paramterTypes[i].isAssignableFrom(args[i].getClass())) {
                            continue outer;
                        }
                    }

                    m = m0;
                    break outer;
                }
            }
        }

        if (m != null) {
            // 对于原型bean,可以缓存找到的方法，方便下次构造实例对象。在BeanDefinfition中获取设置所用方法的方法。
            // 同时在上面增加从beanDefinition中获取的逻辑。
            if (bd.isPrototype()) {
                bd.setFactoryMethod(m);
            }
            return m;
        } else {
            throw new Exception("不存在对应的构造方法！" + bd);
        }
    }
    // 给入属性依赖
    private void setPropertyDIValues(BeanDefinition bd, Object instance) throws Exception {
        if (CollectionUtils.isEmpty(bd.getPropertyValues())) {
            return;
        }
        for (PropertyValue pv : bd.getPropertyValues()) {
            if (!StringUtils.isEmpty(pv.getName())) {
                continue;
            }
            Class<?> clazz = instance.getClass();
            Field p = clazz.getDeclaredField(pv.getName());

            p.setAccessible(true);
            p.set(instance, this.getOneArgumentRealValue(pv.getValue()));

        }
    }


}
